<template>
  <div
    :class="{ fullscreen: fullscreen }"
    class="tinymce-container"
    :style="{ width: containerWidth }"
  >
    <textarea :id="tinymceId" class="tinymce-textarea" />
  </div>
</template>

<script>
/**
 * docs:
 * https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
 */
import plugins from "./plugins";
import toolbar from "./toolbar";
import load from "./dynamicLoadScript";

// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
// http://cdn.jsdelivr.net无法访问了,将cdn.jsdelivr.net域名替换为fastly.jsdelivr.net或者gcore.jsdelivr.net
// const tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'
const tinymceCDN =
  "https://fastly.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js";
import {
  showErrorToast,
  showLoading,
  showSuccessToast,
  closeLoading
} from "@/utils/common";
import service from "@/utils/system/request";
import { ElLoading, ElMessage, ElMessageBox } from "element-plus";

export default {
  name: "Tinymce",
  props: {
    id: {
      type: String,
      default: function () {
        return (
          "vue-tinymce-" +
          +new Date() +
          ((Math.random() * 1000).toFixed(0) + "")
        );
      }
    },
    modelValue: {
      type: String,
      default: ""
    },
    toolbar: {
      type: Array,
      required: false,
      default() {
        return [];
      }
    },
    menubar: {
      type: String,
      default: "file edit insert view format table"
    },
    height: {
      type: [Number, String],
      required: false,
      default: 600
    },
    width: {
      type: [Number, String],
      required: false,
      default: "auto"
    }
  },
  data() {
    return {
      hasChange: false,
      hasInit: false,
      tinymceId: this.id,
      splitImages: [],
      fullscreen: false,
      longImage: null,
      shortImages: [],
      languageTypeList: {
        en: "en",
        zh: "zh_CN",
        es: "es_MX",
        ja: "ja"
      }
    };
  },
  computed: {
    language() {
      return this.languageTypeList["zh"];
    },
    containerWidth() {
      const width = this.width;
      if (/^[\d]+(\.[\d]+)?$/.test(width)) {
        // matches `100`, `'100'`
        return `${width}px`;
      }
      return width;
    }
  },
  watch: {
    // value(newVal, oldVal) {
    //   // console.log(this.hasChange, this.hasInit);
    //   if (!this.hasChange && this.hasInit) {
    //     this.$nextTick(() => {
    //       window.tinymce && window.tinymce.get(this.tinymceId).setContent(newVal || '')
    //       // 让光标定位到未尾
    //
    //       window.tinymce.activeEditor.selection.select(window.tinymce.activeEditor.getBody(), true)
    //       window.tinymce.activeEditor.selection.collapse(false)
    //     })
    //   }
    // value(val) {
    //   if (!this.hasChange && this.hasInit) {
    //     this.$nextTick(() =>
    //       window.tinymce.get(this.tinymceId).setContent(val || "")
    //     );
    //   }
    // },
    modelValue(newVal, oldVal) {
      // if (!this.hasChange && this.hasInit) {
      if (this.hasInit && this.getContent() !== newVal) {
        // if (this.getContent() !== newVal) {
        this.$nextTick(() => {
          window.tinymce &&
            window.tinymce.get(this.tinymceId).setContent(newVal || "");
          // 让光标定位到未尾
          // window.tinymce.activeEditor.selection.select(
          //   window.tinymce.activeEditor.getBody(),
          //   true
          // );
          // window.tinymce.activeEditor.selection.collapse(false);
        });
        // }
        // this.$nextTick(() =>
        //   window.tinymce.get(this.tinymceId).setContent(val || "")
        // );
      }
    },
    language() {
      // this.destroyTinymce()
      this.$nextTick(() => this.initTinymce());
    }
  },
  mounted() {
    this.init();
  },
  activated() {
    if (window.tinymce) {
      this.initTinymce();
    }
  },
  deactivated() {
    this.destroyTinymce();
  },
  unmounted() {
    this.destroyTinymce();
  },
  methods: {
    uploadFile(formData) {
      // 上传图片接口，【可更换】
      console.log(formData);
      return new Promise((resolve, reject) => {
        service.post(`admin/upload/image`, formData).then(({ code, data }) => {
          // closeLoading();
          if (code === 0) {
            showSuccessToast("上传成功");
            resolve(data);
          } else {
            showErrorToast("上传出现了点问题");
            reject();
          }
        });
      });
    },
    init() {
      // dynamic load tinymce from cdn
      load(tinymceCDN, err => {
        if (err) {
          this.$message.error(err.message);
          return;
        }
        this.initTinymce();
      });
    },
    uploadBase64Image(dataURL) {
      // 上传base64的方法
      // 将base64编码的字符串转换为Blob对象
      // 需要将dataURL的头部信息去掉（去掉"data:image/png;base64,"）
      function dataURItoBlob(dataURI) {
        // 分离base64编码的头部信息
        var byteString = atob(dataURI.split(",")[1]);
        // 创建一个内存的ArrayBuffer
        var mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
        var arrayBuffer = new ArrayBuffer(byteString.length);
        var ia = new Uint8Array(arrayBuffer);
        // 将Hex值填充到ArrayBuffer
        for (var i = 0; i < byteString.length; i++) {
          ia[i] = byteString.charCodeAt(i);
        }
        // 通过ArrayBuffer和MIME类型创建Blob对象
        return new Blob([arrayBuffer], { type: mimeString });
      }

      return new Promise((resolve, reject) => {
        var blob = dataURItoBlob(dataURL);
        let formData = new FormData();
        const now = new Date();
        const timeAxis = now.getTime();
        console.log(timeAxis); // 输出时间轴（毫秒数）
        formData.append("fileData", blob, `${timeAxis}image.png`);
        service.post(`admin/upload/image`, formData).then(({ code, data }) => {
          if (code === 0) {
            resolve(data);
          } else {
            // c("上传出现了点问题");
            reject(code);
          }
        });
      });
    },

    initTinymce() {
      let loadingInstance = null;
      const _this = this;
      window.tinymce.init({
        language: this.language,
        selector: `#${this.tinymceId}`,
        height: this.height,
        body_class: "panel-body",
        branding: false,
        object_resizing: true,
        toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
        menubar: this.menubar,
        plugins: plugins,
        toolbar_drawer: true,
        end_container_on_empty_block: true,
        powerpaste_word_import: "clean",
        paste_data_images: true, //允许粘贴base64图片
        paste_enable_default_filters: false, //word文本设置
        code_dialog_height: 450,
        code_dialog_width: 1000,
        images_reuse_filename: true,
        image_advtab: true,
        advlist_bullet_styles: "default,circle,disc,square",
        //advlist_number_styles: 'default',
        imagetools_cors_hosts: ["www.tinymce.com", "codepen.io"],
        default_link_target: "_blank",
        link_title: true,
        content_style:
          "img {max-width:100%;height:auto;display:block;},video {width:100%;height:auto;display:block;}",
        fontsize_formats: "12px 14px 16px 18px 24px 36px 48px 56px 72px",
        font_formats:
          "微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;",
        nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin
        statusbar: false,
        init_instance_callback: editor => {
          console.log("init_instance_callback", editor);
          console.log(_this.modelValue);
          if (_this.modelValue) {
            editor.setContent(_this.modelValue);
          }
          _this.hasInit = true;
          editor.on("NodeChange Change KeyUp SetContent", () => {
            this.hasChange = true;
            console.log(editor.getContent(), "editor.getContent()");
            // this.$emit("input", editor.getContent());
            this.$emit("update:modelValue", editor.getContent());
          });
        },
        setup(editor) {
          // 定义按钮，
          editor.addButton("mybutton", {
            // 按钮名
            text: "长图上传", // 是否显示图标
            icon: "image",
            onclick: function () {
              let imageNumChunks = 0;

              function createFileInput(
                uploadUrl,
                successCallback,
                errorCallback
              ) {
                const fileInput = document.createElement("input");
                fileInput.type = "file";
                fileInput.accept = "image/*"; // 只允许选择图片文件
                fileInput.addEventListener("change", () => {
                  const file = fileInput.files[0];
                  if (file) {
                    loadingInstance = ElLoading.service({
                      lock: true,
                      text: "请稍等,正在处理图片中...",
                      color: "rgba(255,255,255,0.2)",
                      background: "rgba(39,38,38,0.4)"
                    });
                    try {
                      const reader = new FileReader();
                      reader.onload = async event => {
                        const img = new Image();
                        img.onload = () => {
                          const canvas = document.createElement("canvas");
                          const ctx = canvas.getContext("2d");
                          const chunkHeight = 750; // Adjust as needed
                          const numChunks = Math.ceil(img.height / chunkHeight);
                          const splitImages = [];
                          imageNumChunks = numChunks;

                          async function uploadSequentially(files) {
                            // for (let i = numChunks-1;i > -1; i--) {
                            for (let i = 0; i < numChunks; i++) {
                              canvas.width = img.width;
                              canvas.height = Math.min(
                                chunkHeight,
                                img.height - i * chunkHeight
                              );
                              ctx.clearRect(0, 0, canvas.width, canvas.height);
                              ctx.drawImage(
                                img,
                                0,
                                i * chunkHeight,
                                canvas.width,
                                canvas.height,
                                0,
                                0,
                                canvas.width,
                                canvas.height
                              );
                              splitImages.push(canvas.toDataURL());
                              await _this
                                .uploadBase64Image(
                                  canvas.toDataURL("image/jpeg", 0.4)
                                )
                                .then(data => {
                                  successCallback(
                                    data,
                                    `${Math.random().toFixed(4)}${i}`
                                  );
                                });
                            }
                          }

                          uploadSequentially();
                        };
                        img.src = event.target.result;
                      };
                      reader.readAsDataURL(file);
                    } catch (err) {
                      console.log(err);
                    }
                  }
                });
                return fileInput;
              }

              const uploadUrl = "YOUR_UPLOAD_URL"; // 替换为实际的上传图片的 URL
              let uploadNum = 0; // 为实际的上传图片的数量
              const successCallback = (data, name) => {
                uploadNum++;
                if (imageNumChunks == uploadNum) {
                  loadingInstance.close();
                  showSuccessToast("上传成功");
                }
                editor.execCommand(
                  "mceInsertContent",
                  false,
                  `<img src='${data}'/> `
                );
                console.log(name, data, "name");
              };
              const errorCallback = message => {
                console.error(message);
              };
              const fileInput = createFileInput(
                uploadUrl,
                successCallback,
                errorCallback
              );
              // document.body.appendChild(fileInput);
              // 触发上传
              fileInput.click();
            }
          });
          editor.on("FullscreenStateChanged", e => {
            _this.fullscreen = e.state;
          });
        },
        // it will try to keep these URLs intact
        // https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/
        // https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions
        convert_urls: false,
        images_upload_handler: async (blobInfo, success, failure) => {
          try {
            let formData = new FormData();
            formData.append("fileData", blobInfo.blob());
            this.uploadFile(formData).then(res => {
              console.log(res);
              success(res);
            });
          } catch (err) {
            console.log(err);
          }
        }
      });
    },
    destroyTinymce() {
      const tinymce = window.tinymce.get(this.tinymceId);
      if (this.fullscreen) {
        tinymce.execCommand("mceFullScreen");
      }

      if (tinymce) {
        tinymce.destroy();
      }
    },
    setContent(value) {
      window.tinymce.get(this.tinymceId).setContent(value);
    },
    getContent() {
      return window.tinymce.get(this.tinymceId).getContent();
    },
    imageSuccessCBK(arr) {
      arr.forEach(v =>
        window.tinymce
          .get(this.tinymceId)
          .insertContent(`<img class="wscnph" src="${v.url}" >`)
      );
    }
  }
};
</script>

<style lang="less" scoped>
.tinymce-container {
  position: relative;
  line-height: normal;
  :deep(*) {
    border-color: #efefef;
    white-space: pre-wrap;
  }
}

.tinymce-container {
  :deep(*) {
    .mce-fullscreen {
      z-index: 10000;
    }
  }
}

.tinymce-textarea {
  visibility: hidden;
  z-index: -1;
}

.editor-custom-btn-container {
  position: absolute;
  right: 4px;
  top: 4px;
  /*z-index: 2005;*/
}

.fullscreen .editor-custom-btn-container {
  z-index: 10000;
  position: fixed;
}

.editor-upload-btn {
  display: inline-block;
}
</style>
